//@ts-nocheck
import React, { useEffect, useMemo, useRef } from 'react';

class Dispatcher {
  callbacks = {};
  data = {};
  update = (namespace) => {
    if (this.callbacks[namespace]) {
      this.callbacks[namespace].forEach((cb) => {
        try {
          const data = this.data[namespace];
          cb(data);
        } catch (e) {
          cb(undefined);
        }
      });
    }
  };
  remove = (namespace) => {
    if (this.data[namespace]) {
      delete this.data[namespace];
    }
    if (this.callbacks[namespace]) {
      delete this.callbacks[namespace];
    }
  };
}

const dispatcher = new Dispatcher();

export const Context = React.createContext(null);

function Executor(props) {
  const { hook, onUpdate, namespace } = props;

  const updateRef = useRef(onUpdate);
  const initialLoad = useRef(false);

  let data;
  try {
    data = hook();
  } catch (e) {
    console.error(
      `plugin-model: Invoking '${namespace || 'unknown'}' model failed:`,
      e,
    );
  }

  // 首次执行时立刻返回初始值
  useMemo(() => {
    updateRef.current(data);
  }, []);

  // React 16.13 后 update 函数用 useEffect 包裹
  useEffect(() => {
    if (initialLoad.current) {
      updateRef.current(data);
    } else {
      initialLoad.current = true;
    }
  });

  return null;
}

export function Provider(props) {
  useEffect(() => {
    return () => {
      Object.keys(props.models).map((key) => {
        dispatcher.remove(key);
      });
    };
  }, []);
  return (
    <Context.Provider value={{ dispatcher }}>
      {Object.keys(props.models).map((namespace) => {
        return (
          <Executor
            key={namespace}
            hook={props.models[namespace]}
            namespace={namespace}
            onUpdate={(val) => {
              dispatcher.data[namespace] = val;
              dispatcher.update(namespace);
            }}
          />
        );
      })}
      {props.children}
    </Context.Provider>
  );
}
